<?php 

namespace fuiou;
/**
* 富友支付类
*/
class FuiouApi 
{
	public $error = '';
	function __construct()
	{
		$this->FuiouConfig = config('fauiou');
		//富友中心
		$this->FuiouCenterConfig = config('fauiou_center');
		$this->memo = config('fuyou_channel');
    }

	/**
	 * 代付 商户打款给用户
	 * 最终打款结果以回调或查询接口为准
	 * @author   yhq <934797303@qq.com>
	 * @DateTime 2018-03-21T18:36:23+0800
	 * @param    [array]    $param [请求参数]
	 * @return   [array]           [富友返回的打款结果]
	 */
	public function pay($param)
	{
	    if(is_array($this->FuiouCenterConfig)){
            $param['memo'] = $this->memo;
            $res = curlPost($this->FuiouCenterConfig['fuiou_pay_url'],$param);
            $res = json_decode($res,true);
            return $res;
        }


		#### 请参数示例 ####
		// $param = [
		// 	'orderno'  => "20180322489956561",   // 请求流水 数字串，当天必须唯一
		// 	'bankno'   => '0104',               // 总行代码
		// 	'cityno'   => '5210',               // 城市代码
		// 	'branchnm' => '',                   // 支行名称 可不填，如果填写，一定要填对，否则影响交易；但对公户、城商行、农商行、信用社必须填支行，且需正确的支行信息
		// 	'amt'      => '300',                // 金额 单位：分（单笔最少 3 元）
		// 	'accntno'  => '6217857600005935445',// 用户银行账号
		// 	'accntnm'  => '杨华强',             // 用户账户名称
		// 	'mobile'   => '18675532019',        // 手机号  短信通知时使用  可不填
		// 	'entseq'   => '',                   // 企业流水号 填写后，系统体现在交易查询中 可不填
		// 	'memo'     => '',                   // 备注  填写后，系统体现在交易查询中 可不填
		// ];
		#### 请参数示例 ####

		$ver      = "2.00";
		$merdt    = date("Ymd");
		$reqtype  = "payforreq";  
		$orderno  = $param['orderno'];
		$bankno   = $param['bankno'];  
		$cityno   = empty($param['cityno']) ? '1000' : $param['cityno'];  
		$branchnm = $param['branchnm'];  
		$amt      = $param['amt']; 
		$accntno  = $param['accntno']; 
		$accntnm  = $param['accntnm']; 
		$mobile   = empty($param['mobile']) ? '' : $param['mobile']; 
		$entseq   = empty($param['entseq']) ? '' : $param['entseq']; 
		$memo     = empty($param['memo']) ? '' : $param['memo']; 
		$addDesc  = 1; 

		$xml = "<?xml version='1.0' encoding='utf-8' standalone='yes'?><payforreq><ver>".$ver."</ver><merdt>".$merdt."</merdt><orderno>".$orderno."</orderno><bankno>".$bankno."</bankno><cityno>".$cityno."</cityno><accntno>".$accntno."</accntno><accntnm>".$accntnm."</accntnm><branchnm>".$branchnm."</branchnm><amt>".$amt."</amt><mobile>".$mobile."</mobile><entseq>".$entseq."</entseq><memo>".$memo."</memo><addDesc>".$addDesc."</addDesc></payforreq>";

		$result = $this->request($reqtype, $xml);
		$result['orderno'] = $orderno;
		$result['time'] = date('Y-m-d H:i:s');
		return $result;

		#### 结果示例 
		// array(3) {
		// 	["ret"] => string(6) "000000"
		// 	["memo"] => string(6) "成功"
		// 	["transStatusDesc"] => string(12) "受理成功"
		// 	["orderno"] => string(16) "2018032248991111"
		// 	["time"] => string(19) "2018-03-30 16:06:12"
		// }
	}



	/**
	 * 查询代付结果
	 * 生产查询间隔为3分钟。关于批量查询，可以不填请求流水，查询时间段的所有交易。也可以一次查询多个流水，流水之间用”,”英文逗号分隔，最多 50 个。
	 * @author   yhq <934797303@qq.com>
	 * @DateTime 2018-03-22T11:56:24+0800
	 * @param    [string|array]     $orderno [订单号 数组则为批量查询 最大50个 间隔3分钟]
	 * @return   [array]                     [结果]
	 */
	public function payResQuery($orderno, $type = 0)
	{
	    //富友中心
        if(is_array($this->FuiouCenterConfig)){
            $param['memo'] = $this->memo;
            $param['orderno'] = $orderno;
            $res = curlPost($this->FuiouCenterConfig['fuiou_payres_url'],$param);
            $res = json_decode($res,true);
            return $res;
        }

		#### 请参数示例 ####
		// 单个订单	
		// $orderno = '20180322489956561';
		// 
		// 或者批量
		// $orderno = [
		// 	'20180322489956561',
		// 	'20180322489956562',
		// 	'20180322489956563',
		// 	'20180322489956564',
		// ];
		#### 请参数示例 ####

		// 批量查询
		if(is_array($orderno)){
			$orderno = implode(',', $orderno);
		}

		$ver     = '1.1';
		$busicd  = $type ? 'AC01' :'AP01';
		$reqtype = "qrytransreq";
		$orderno = $orderno;
		$startdt = date("Ymd",time()-14*24*3600);
		$enddt   = date("Ymd");

		$xml = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>
		<qrytransreq>
		<ver>'.$ver.'</ver>
		<busicd>'.$busicd.'</busicd>
		<orderno>'.$orderno.'</orderno>
		<startdt>'.$startdt.'</startdt>
		<enddt>'.$enddt.'</enddt>
		</qrytransreq>';

		$result = $this->request($reqtype, $xml);

		// 统一化返回结果
		if ($result['trans'] && !is_array($result['trans'][0])) {
			$data = $result['trans'];
			foreach ($result['trans'] as $key => $value) {
				unset($result['trans'][$key]);
			}
			$result['trans'][0] = $data;
		}

		return $result;
		
		#### 结果示例
		// array(3) {
		//   ["ret"] => string(6) "000000"
		//   ["memo"] => string(6) "成功"
		//   ["trans"] => array(2) {
		//     [0] => array(10) {
		//       ["merdt"] => string(8) "20180322"
		//       ["orderno"] => string(17) "20180322489956561"
		//       ["accntno"] => string(19) "6217857600005935445"
		//       ["accntnm"] => string(9) "杨华强"
		//       ["amt"] => string(3) "300"
		//       ["entseq"] => string(4) "test"
		//       ["memo"] => string(6) "备注"
		//       ["state"] => string(1) "1"
		//       ["result"] => string(43) "渠道资金到账已复核,交易已发送"
		//       ["reason"] => string(12) "交易成功"
		//     }
		//     [1] => array(10) {
		//       ["merdt"] => string(8) "20180322"
		//       ["orderno"] => string(17) "20180322489956562"
		//       ["accntno"] => string(19) "6217857600005935445"
		//       ["accntnm"] => string(9) "杨华强"
		//       ["amt"] => string(3) "300"
		//       ["entseq"] => array(0) {
		//       }
		//       ["memo"] => array(0) {
		//       }
		//       ["state"] => string(1) "1"
		//       ["result"] => string(43) "渠道资金到账已复核,交易已发送"
		//       ["reason"] => string(12) "交易成功"
		//     }
		//   }
		// }

		#### state 参数
		// 0 交易未发送
		// 1 交易已发送且成功
		// 2 交易已发送且失败
		// 3（需要接口/平台查询确认最终结果） 交易发送中
		// 7（配置二次查询，会有此状态） 交易超时

		#### 付款成功和失败如何确认
		// 成功：接口查询状态state为 1 ，且 T+1 没有退票产生。
		// 失败：失败交易会产生退票。
	}



	/**
	 * 请求函数
	 * @author   yhq <934797303@qq.com>
	 * @DateTime 2018-03-22T12:11:17+0800
	 * @param    [string]     $reqtype [请求类型]
	 * @param    [string]     $xml     [xml]
	 * @return   [array]               [请求结果]
	 */
	protected  function request($reqtype, $xml)
	{
		$merid = $this->FuiouConfig['fuiou_merid'];
		$pwd   = $this->FuiouConfig['fuiou_pwd'];
		$url   = $this->FuiouConfig['fuiou_url'];

		$macsource = $merid."|".$pwd."|".$reqtype."|".$xml;

		$mac = md5($macsource);
		$mac = strtoupper($mac);

		$list = array("merid"=>$merid,"reqtype"=>$reqtype,"xml"=>$xml,"mac"=>$mac);

		$query = http_build_query($list);
		$options = array(
			'http' => array(
				'header'  => "Content-Type: application/x-www-form-urlencoded\r\n".
				"Content-Length: ".strlen($query)."\r\n".
				"User-Agent:MyAgent/1.0\r\n",
				'method'  => "POST",
				'content' => $query,
			),
		);
		$context = stream_context_create($options);

		// dump(urldecode($query));
		// die;
		$result  = file_get_contents($url, false, $context, -1, 40000);

		$result = json_decode($this->xmlToJson($result), true);

		$tips = [
			'success'       => '成功',
			'acceptSuccess' => '受理成功',
			'internalFail'  => '富友失败',
			'channelFail'   => '通道失败',
			'cardInfoError' => '卡信息错误',
			'unknowReasons' => '交易结果未知',
		];
		if(isset($result['transStatusDesc'])){
			$result['transStatusDesc'] = $tips[$result['transStatusDesc']];
		}

		return $result;
	}

	
	/**
	 * [returnSignaTureParam 返回sign以及param]
	 * @param  array  &$param [description]
	 * @return [type]         [description]
	 */
	public function returnSignaTureParam(array &$param = [])
	{
        //富友中心
        if(is_array($this->FuiouCenterConfig)){
            $param['memo'] = $this->memo;
            $res = curlPost($this->FuiouCenterConfig['fuiou_sign_url'],$param);
            $res = json_decode($res,true);
//            var_dump($res);exit;
            return $res;
        }

		$data['srcChnl']      = $param["srcChnl"];//签约来源
		$data['busiCd']       = $param["busiCd"];//业务类型
		$data['bankCd']       = $param['bankCd']; //行别
		$data['userNm']       = $param['userNm']; //户名
		$data['mobileNo']     = $param['mobileNo'];//手机号
		$data['credtTp']      = $param['credtTp'];//证件类型
		$data['credtNo']      = $param['credtNo'];//证件号码
		$data['acntTp']       = $param['acntTp'];//账户类型
		$data['acntNo']       = $param['acntNo'];//银行卡号
		$data['mchntCd']      = $this->FuiouConfig['fuiou_merid'];//商户号
		$data['isCallback']   = "0";//回拨号码
		$data['reserved1']    = "代收签约";//保留字段
		$data['pageFrontUrl'] = $param['pageFrontUrl'];//同步地址
		$shi = $this->signature($data);
		$string = $shi.'|'.$this->FuiouConfig['fuiou_pwd'];
		$datas['signature'] = sha1($string);
		$datas['mchntCd'] = $data['mchntCd'];
		$datas['isCallback'] = $data['isCallback'];
		$datas['reserved1'] = $data['reserved1'];
		$datas['pageFrontUrl'] = $data['pageFrontUrl'];
		return $datas;
	}
	/**
	 * [notifyContract 签约异步回调签名]
	 * @param  array  &$param [description]
	 * @return [type]         [description]
	 */
	public function notifyContract(array &$param = [])
	{
        //富友中心
        if(is_array($this->FuiouCenterConfig)){
            $param['memo'] = $this->memo;
            $res = curlPost($this->FuiouCenterConfig['fuiou_contract_url'],$param);
            return $res;
        }

		$data['mchnt_cd']    = $param["mchnt_cd"];//商户号
		$data['contract_no'] = $param["contract_no"];//协议号
		$data['acnt_no']     = $param['acnt_no']; //银行卡号
		$data['date']        = date('Ymd'); //时间
		$data['contract_st'] = $param['contract_st']; //签约状态
		$data['key']         = $this->FuiouConfig['fuiou_pwd']; //秘钥
		$sign = $this->signature($data,1);
		if($sign != $param['signature'])
		{
			$this->error = '验签失败';
			return false;
		}
		if($data['contract_st'] != 1)
		{
			$this->error = '签约失败';
			return false;
		}
		return '签约成功';
	}
	/**
	 * [signature 生成签名]
	 * @param  array  $param [description]
	 * * @param  int  是否排序 0 是 1否 [description]
	 * @return [type]        [description]
	 */
	public function signature(array $param = [], $is_sort = 0)
	{
		if(!$is_sort)
		{
			sort($param,SORT_STRING);
		}
		$str = implode('|', $param);
		return sha1($str);
	}

	/**
	 * 代付回调验签
	 * @author yhq <934797303@qq.com>
	 * @date   2018-04-02
	 * @param  [array]     $notifyResp [回调参数]
	 * @return [boolean]                
	 */
	public function checkSignature($notifyResp)
	{
		$merid   = $this->FuiouConfig['fuiou_merid'];
		$pwd     = $this->FuiouConfig['fuiou_pwd'];

		$orderno = $notifyResp['orderno'];
		$merdt   = $notifyResp['merdt'];
		$accntno = $notifyResp['accntno'];
		$amt     = $notifyResp['amt'];

		$macsource = $merid."|".$pwd."|".$orderno."|".$merdt."|".$accntno."|".$amt;
		$mac = md5($macsource);

		return ($mac == $notifyResp['mac']) ? true : false;
	}


	/**
	 * xml转换成json
	 */
	public   function xmlToJson($source) {
	    if(is_file($source)){ //传的是文件，还是xml的string的判断
	        $xml_array=simplexml_load_file($source);
	    }else{
	    	$xml_array = @simplexml_load_string($source);
	    	//判断是否转换成功
	    	if(!is_object($xml_array))
	    	{
	    		$xml_array = $this->xml2ToJson($source);
	    	}
	    }

	    $json = json_encode($xml_array);
	    return $json;
	}
	/**
	 * [xml2ToJson 为了应付两个相同的根节点]
	 * @param  string $xml [description]
	 * @return [type]      [description]
	 */
	public function xml2ToJson($xml = '')
	{
		$reg = "/<(\\w+)[^>]*?>([\\x00-\\xFF]*?)<\\/\\1>/";
	    if(preg_match_all($reg, $xml, $matches))
	    {
	        $count = count($matches[0]);
	        $arr = array();
	        for($i = 0; $i < $count; $i++)
	        {
	            $key= $matches[1][$i];
	            $val = $this->xml2ToJson( $matches[2][$i] );  // 递归
	            if(array_key_exists($key, $arr))
	            {
	                if(is_array($arr[$key]))
	                {
	                    if(!array_key_exists(0,$arr[$key]))
	                    {
	                        $arr[$key] = array($arr[$key]);
	                    }
	                }else{
	                    $arr[$key] = array($arr[$key]);
	                }
	                $arr[$key][] = $val;
	            }else{
	                $arr[$key] = $val;
	            }
	        }
	        return $arr;
	    }else{
	        return $xml;
	    }
	}	
	/**
	 * [project 项目录入]
	 * @param  array  &$param [description]
	 * @return [type]         [description]
	 */
	public function project(array &$param = [])
	{
        //富友中心
        if(is_array($this->FuiouCenterConfig)){
            $param['memo'] = $this->memo;
            $res = curlPost($this->FuiouCenterConfig['projecturl'],$param);
            $res = json_decode($res,true);
//            $res = json_decode($res,true);
            return $res;
        }

		$data['ver'] = '2.00';//版本号
		$data['orderno'] = $param['orderno'];//请求流水
		$data['mchnt_nm'] = '风水钱庄代收';//商户名称
		$data['project_ssn'] = substr(strval(rand(1000000, 1999999)), 1,6);//项目序列号
		$data['project_amt'] = $param['project_amt'] * 100;//项目金额(分)
		$data['contract_nm'] = $param['contract_nm'];//商户借款合同编号
		$data['project_deadline'] = $param['project_deadline'];//项目期限
		$data['max_invest_num'] = '';
		$data['min_invest_num'] = '';
		$data['bor_nm'] = $param['bor_nm'];//借款人姓名
		$data['id_tp'] = '0';//借款人证件类型
		$data['id_no'] = $param['id_no'];//借款人证件号码
		$data['card_no'] = $param['card_no'];//借款人卡号
		$data['mobile_no'] = $param['mobile_no'];//借款人手机号码
		$xml = $this->arrayToXml($data,'project');
		//拼接
		$macsource = $this->FuiouConfig['fuiou_merid']."|".$this->FuiouConfig['fuiou_pwd']."|".$xml;
		//echo $xml;
		$mac=md5($macsource);
		$mac=strtoupper($mac);
		$list=array("merid"=>$this->FuiouConfig['fuiou_merid'],"xml"=>$xml,"mac"=>$mac);
		//获取数据
		return $this->requestGet($list,$this->FuiouConfig['projecturl']);
	}
	/**
	 * [cardList 查询银行卡列表]
	 * @return [type] [description]
	 */
	public function cardList(array &$param = [])
	{
        //富友中心
        if(is_array($this->FuiouCenterConfig)){
            $param['memo'] = $this->memo;
            $res = curlPost($this->FuiouCenterConfig['fuiou_query_url'],$param);
            return $res;
        }

		$data['ver']        = "1.00";
		$data['mchntCd']    = $this->FuiouConfig['fuiou_merid'];
		$data['startdt']    = $param['startdt'];//开始日期
		$data['enddt']      = $param['enddt'];//结束日期
		$data['mobileNo']   = $param['mobileNo'];//手机号
		$data['userNm']     = $param['userNm'];//户名
		$data['credtNo']    = $param['credtNo'];//身份证号
		//获取sign
		$shi = $this->signature($data);
		$string = $shi.'|'.$this->FuiouConfig['fuiou_pwd'];
		$data['signature'] = sha1($string);
		//不参与签名
		$data['contractNo'] = $param['contractNo'];//协议号
		$data['acntNo']     = $param['acntNo'];//银行卡号
		//转数据格式
		$xml =  $this->arrayToXml($data,'custmrBusi');
		$list=array("xml"=>$xml);
		//获取数据
		return $this->requestGet($list,$this->FuiouConfig['fuiou_query_url']);
	}
	/**
	 * [incomforreq 代收]
	 * @param  array  &$param [description]
	 * @return [type]         [description]
	 */
	public function incomforreq(array &$param = [])
	{
        //富友中心
        if(is_array($this->FuiouCenterConfig)){
            $param['memo'] = $this->memo;
            $res = curlPost($this->FuiouCenterConfig['fuiou_incomforreq_url'],$param);
            $res = json_decode($res,true);
            return $res;
        }

		$data['ver']       = "2.00";//版本号
		$data['merdt']     = date('Ymd');//请求日期
		$data['orderno']   = $param['orderno'];//请求流水
		$data['bankno']    = $param['bankno'];//总行代码 
		$data['accntno']   = $param['accntno'];//账号
		$data['accntnm']   = $param['accntnm'];//账户名称
		$data['amt']       = $param['amt'];//金额(分)
		$data['certtp']    = '0';//证件类型
		$data['certno']    = $param['certno'];//证件号
		$data['mobile']    = $param['mobile'];//手机号
		$data['entseq']    = $param['entseq'];//企业流水号
		$data['memo']      = $param['memo'];//备注
		$data['projectid'] = $param['projectid'];//项目id
		$data['txncd']     = $param['txncd'];//业务定义
		$xml =  $this->arrayToXml($data,'incomeforreq');
		$reqtype = "sincomeforreq";
		$macsource = $this->FuiouConfig['fuiou_merid'] ."|". $this->FuiouConfig['fuiou_pwd'] ."|".$reqtype."|".$xml;
		$mac = strtoupper(md5($macsource));
		$list=array("merid"=>$this->FuiouConfig['fuiou_merid'],"reqtype"=>$reqtype,"xml"=>$xml,"mac"=>$mac);
		//获取数据
		return $this->requestGet($list,$this->FuiouConfig['fuiou_url']);
	}
	/**
	 * [requestGet 获取数据]
	 * @param  string $data [description]
	 * @param  string $url  [description]
	 * @return [type]       [description]
	 */
	public function requestGet($data = '', $url = '')
	{
		$query = http_build_query($data);
		$options = array(
		    'http' => array(
		        'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
		                    "Content-Length: ".strlen($query)."\r\n".
		                    "User-Agent:MyAgent/1.0\r\n",
		        'method'  => "POST",
		        'content' => $query,
		    ),
		);
		$context = stream_context_create($options);
		$result = file_get_contents($url, false, $context, -1, 40000);
		return $this->xmlToJson($result);
	}
	/**
	* 数组转xml
	 */
	public  function arrayToXml(array $arr, $title = '', $dom=0, $item=0){ 
	    if (!$dom){ 
	        $dom = new \DOMDocument("1.0", 'utf-8'); 
	    } 
	    if(!$item){ 
	        $item = $dom->createElement($title); 
	        $dom->appendChild($item); 
	    } 
	    foreach ($arr as $key=>$val){ 
	        $itemx = $dom->createElement(is_string($key)?$key:"item"); 
	        $item->appendChild($itemx); 
	        if (!is_array($val)){ 
	            $text = $dom->createTextNode($val);
	            $itemx->appendChild($text); 
	         
	        }else { 
	            arrayToXml($val,$title,$dom,$itemx); 
	        }
	    } 
	    return $dom->saveXML(); 
	}
}